﻿using System.Configuration;
using Selenium;
using SeleniumToolkit.Config;
using System.Collections.Generic;
using System;

namespace SeleniumToolkit.Core
{
    /// <summary>
    /// Constructs ISelenium instances based on configuration settings
    /// </summary>
    public sealed class SeleniumFactory
    {
        private static SeleniumFactory _instance;
        private readonly SeleniumConfiguration _config;
        private readonly ISeleniumFactoryProvider _provider;
        private readonly Dictionary<string, string> _browsers;

        /// <summary>
        /// Configures the Selenium Factory with the defined configuration
        /// </summary>
        /// <param name="config">configuration settings to use</param>
        public static void Configure(SeleniumConfiguration config)
        {
            Configure(config, null);
        }

        /// <summary>
        /// Configures the Selenium Factory with a configuration and factory provider
        /// </summary>
        /// <param name="config">configuration settings to use</param>
        /// <param name="provider">factory provider to use (allows custom selenium instances to be used)</param>
        public static void Configure(SeleniumConfiguration config, ISeleniumFactoryProvider provider)
        {
            if (config == null)
                config = new SeleniumConfiguration();

            if (provider == null)
                provider = config.ResolveFactory();

            _instance = new SeleniumFactory(config, provider);
        }

        /// <summary>
        /// Create a selenium browser with the default settings
        /// </summary>
        /// <returns></returns>
        public static ISelenium Create()
        {
            return _instance.CreateInstance();
        }

        /// <summary>
        /// Create a selenium browser
        /// </summary>
        /// <param name="browserString">the browser instance to spawn</param>
        /// <returns></returns>
        public static ISelenium Create(string browserString)
        {
            return _instance.CreateInstance(browserString);
        }

        /// <summary>
        /// Create a selenium browser with a specific browser
        /// </summary>
        /// <param name="browserString">the browser instance to spawn</param>
        /// <param name="baseUrl">the base url</param>
        /// <returns></returns>
        public static ISelenium Create(string browserString, string baseUrl)
        {
            return _instance.CreateInstance(browserString, baseUrl);
        }

        #region instance members

        /// <summary>
        /// Default Constructor
        /// </summary>
        /// <param name="config">configuration settings</param>
        /// <param name="provider">factory provider (null to use default)</param>
        public SeleniumFactory(SeleniumConfiguration config, ISeleniumFactoryProvider provider)
        {
            _config = config;
            _provider = provider;

            _browsers = _config.Browsers == null ? 
                            new Dictionary<string,string>() :
                            _config.Browsers.ToDictionary();
        }

        /// <summary>
        /// Create a selenium instance using the configuration settings
        /// </summary>
        /// <returns>Returns a Selenium instance</returns>
        public ISelenium CreateInstance()
        {
            return CreateInstance(_config.SeleniumServer,
                          _config.SeleniumServerPort,
                          _config.DefaultBrowser,
                          _config.BrowserUrl);
        }

        /// <summary>
        /// Create a selenium instance using the supplied browser and default configuration settings
        /// </summary>
        /// <param name="browserString">one of the defined browser strings</param>
        /// <returns>Returns a Selenium instance</returns>
        public ISelenium CreateInstance(string browserString)
        {
            return CreateInstance(_config.SeleniumServer, _config.SeleniumServerPort, browserString, _config.BrowserUrl);
        }

        /// <summary>
        /// Create a selenium instance using the supplied browser and url, default the remaining settings to configuration values
        /// </summary>
        /// <param name="browserString">one of the defined browser strings</param>
        /// <param name="browserUrl">the url of the site</param>
        /// <returns>Returns a Selenium instance</returns>
        public ISelenium CreateInstance(string browserString, string browserUrl)
        {
            return CreateInstance(_config.SeleniumServer, _config.SeleniumServerPort, browserString, browserUrl);
        }

        /// <summary>
        /// Create a selenium instance using custom settings
        /// </summary>
        /// <param name="serverHost">the selenium remote control server name</param>
        /// <param name="serverPort">the selenium remote control port</param>
        /// <param name="browserString">the defined browser string</param>
        /// <param name="browserUrl">the url for the browser</param>
        /// <returns>Returns a Selenium instance</returns>
        public ISelenium CreateInstance(string serverHost, int serverPort, string browserString, string browserUrl)
        {
            string browser = _browsers[browserString];
            return _provider.Create(serverHost, serverPort, browser, browserUrl);
        }

        /// <summary>
        /// A mapping table of browsers to their selenium supported names
        /// </summary>
        public Dictionary<string, string> BrowserMap
        {
            get { return _browsers; }
        }

        #endregion

    }

    
}
